<template>
  <div
    class="chart-box"
    style="width: 100%; height: 100%"
    :style="{ backgroundColor: widgetOptions.setup.backgroundColor }"
  >
    <div v-if="!chartStatus" ref="chartRef" style="width: 100%; height: 100%"></div>
    <div class="table-box" v-if="isViewDetail && tableData">
      <table cellpadding="2" :style="{ color: widgetOptions.setup.subChart_tableFontColor }">
        <tbody>
          <tr v-for="(value, key) in tableData" :key="key">
            <td>{{ key }}</td>
            <td>{{ transKeyToName('' + key) }}</td>
            <td>{{ formatNumber(value, 2) }}</td>
          </tr>
        </tbody>
      </table>
    </div>
    <ChartEmpty v-if="chartStatus" :chartStatus="chartStatus" />
  </div>
</template>

<script lang="ts" setup>
import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
import * as echarts from 'echarts'
import { useTools } from '../../hooks/useTools'
import { useWidgetTools } from '../../hooks/useWidgetTools'
import { mapper } from '../constants'
import { useSignalView } from '../../hooks/useSignalView'
import ChartEmpty from '../../components/chartEmpty.vue'

// 接收父组件传入的值
const props = defineProps({
  widgetOptions: {
    type: Object as PropType<Record<string, any>>, // 或更具体的类型
    required: true
  },
  isPreview: {
    type: Boolean,
    default: false
  }
})

const chartRef = ref<HTMLDivElement | null>(null)
let myChart: echarts.ECharts | null = null
const chartData = ref<any>(null)
const { renderErrorBar, renderHistogram, formatNumber, transKeyToName } = useWidgetTools()

const isViewDetail = ref(false)
const tableData = ref<any>()

const { toRgba } = useTools()
const mockDataUrl = '/mockdata/history/splAStatistics.json'

const initChart = () => {
  if (chartRef.value) {
    // 初始化实例
    myChart = echarts.init(chartRef.value)

    myChart?.on('dblclick', function (params) {
      const { name } = params
      const data = chartData.value.find((item) => item.startTime === name)
      if (!data) {
        return
      }
      drawDetailChart(data)
    })
  }
}

const beforeUpdateOption = () => {
  myChart?.clear()
  const option = {
    title: {
      text: `趋势图1`,
      subtext: '双击图表，查看详细信息',
      left: 'center',
      textStyle: {
        color: props.widgetOptions.setup.titleColor,
        fontSize: props.widgetOptions.setup.titleFontSize
      },
      subtextStyle: {
        color: props.widgetOptions.setup.subtitleColor,
        fontSize: props.widgetOptions.setup.subtitleFontSize
      }
    },
    tooltip: {
      trigger: 'axis'
    },
    grid: {
      top: '65'
    },
    legend: {
      top: '50',
      selectedMode: 'single',
      itemStyle: {
        color: props.widgetOptions.setup.legendColor
      },
      textStyle: {
        color: props.widgetOptions.setup.legendFontColor,
        fontSize: props.widgetOptions.setup.legendFontSize
      }
    },
    xAxis: {
      type: 'category',
      axisLine: {
        show: true,
        lineStyle: {
          color: props.widgetOptions.setup.xLineColor
        }
      },
      axisLabel: {
        color: props.widgetOptions.setup.xFontColor,
        fontSize: props.widgetOptions.setup.xFontSize
      }
    },
    yAxis: {
      type: 'value',
      scale: true,
      axisLabel: {
        color: props.widgetOptions.setup.yFontColor,
        fontSize: props.widgetOptions.setup.yFontSize
      },
      splitLine: {
        show: props.widgetOptions.setup.ySplitLine,
        lineStyle: {
          color: 'rgba(255,255,255,0.2)'
        }
      }
    }
  }
  myChart?.setOption(option)
}

// 更新配置
const updateOptions = () => {
  if (!chartData.value) return
  beforeUpdateOption()
  const items = chartData.value
  const seriesDataBoxplot: any[] = []
  const seriesDataBar: any[] = []
  const seriesDataError: any[] = []
  let yMin = Number.MAX_VALUE
  for (let i = 0; i < items.length; i++) {
    const { startTime, value } = items[i]
    const { avg, se, min, max, median, percentile25, percentile75 } = value
    seriesDataBoxplot.push([min, percentile25, median, percentile75, max])
    seriesDataBar.push(avg)
    seriesDataError.push([startTime, avg - se, avg + se])
    yMin = Math.min(yMin, min)
  }
  yMin = +Math.floor(yMin).toFixed(0)
  const series: any[] = []
  series.push({
    name: 'boxplot',
    type: 'boxplot',
    data: seriesDataBoxplot,
    itemStyle: {
      color: props.widgetOptions.setup.boxplotColor
    }
  })
  series.push({
    name: 'mean-error',
    type: 'bar',
    data: seriesDataBar,
    label: {
      show: true,
      position: 'inside',
      formatter: function (params) {
        return params.value.toFixed(2)
      }
    }
  })
  series.push({
    name: 'mean-error',
    type: 'custom',
    itemStyle: {
      borderWidth: 1.5,
      color: 'red'
    },
    data: seriesDataError,
    renderItem: renderErrorBar,
    encode: { tooltip: [1, 2] },
    z: 100
  })
  const xData = items.map((item) => item.startTime)
  const option = {
    xAxis: {
      data: xData
    },
    yAxis: {
      min: yMin
    },
    series
  }

  myChart?.setOption(option)
  myChart?.resize()
}

const reload = () => {
  beforeUpdateOption()
  updateOptions()
}

const drawDetailChart = (msg) => {
  isViewDetail.value = true
  myChart?.clear()
  const { signalName, startTime, duration, value, extra } = msg
  const signalLabel = mapper[signalName] || ''
  const series: any[] = []
  const { hist, avg, se, median, min, max, percentile25, percentile75 } = value
  series.push({
    name: 'mean',
    type: 'bar',
    barWidth: '30%',
    xAxisIndex: 0,
    yAxisIndex: 0,
    data: [avg],
    label: {
      show: true,
      position: 'inside'
    },
    itemStyle: {
      color: props.widgetOptions.setup.subChart_barColor
    }
  })
  series.push({
    name: 'standard error',
    type: 'custom',
    itemStyle: {
      borderWidth: 1.5,
      color: 'red'
    },
    xAxisIndex: 0,
    yAxisIndex: 0,
    data: [[startTime, avg - se, avg + se]],
    renderItem: renderErrorBar,
    encode: { tooltip: [1, 2] },
    z: 100
  })
  series.push({
    name: 'boxplot',
    type: 'boxplot',
    xAxisIndex: 1,
    yAxisIndex: 1,
    itemStyle: {
      color: props.widgetOptions.setup.subChart_boxplotColor
    },
    data: [[min, percentile25, median, percentile75, max]]
  })
  const histData = hist.map((p) => [...p, p[0].toFixed(2) + '-' + p[1].toFixed(2)])
  series.push({
    name: 'histogram',
    data: histData,
    type: 'custom',
    renderItem: renderHistogram,
    encode: {
      label: [3, 2]
    },
    xAxisIndex: 2,
    yAxisIndex: 2,
    label: {
      show: true,
      position: 'right',
      formatter: function (params) {
        const { data } = params
        return '范围：' + data[3] + '  数量：' + data[2]
      }
    },
    tooltip: {
      show: false
    },
    itemStyle: {
      color: props.widgetOptions.setup.subChart_rectColor
    }
  })

  const yMin = +Math.floor(min).toFixed(0)
  const yMax = +Math.ceil(max).toFixed(0)
  const xMax = Math.max(...hist.map((p) => p[2]))
  const xData = [startTime]
  const option = {
    title: {
      text: `最近${duration}秒${signalLabel}`,
      subtext: `开始时间：${startTime}`,
      left: 'center',
      textStyle: {
        color: props.widgetOptions.setup.titleColor,
        fontSize: props.widgetOptions.setup.titleFontSize
      },
      subtextStyle: {
        color: props.widgetOptions.setup.subtitleColor,
        fontSize: props.widgetOptions.setup.subtitleFontSize
      }
    },
    tooltip: {
      trigger: 'axis'
    },
    legend: {
      top: '10%',
      itemStyle: {
        color: props.widgetOptions.setup.legendColor
      },
      textStyle: {
        color: props.widgetOptions.setup.legendFontColor,
        fontSize: props.widgetOptions.setup.legendFontSize
      }
    },
    grid: [
      {
        top: '10%',
        left: '5%',
        right: '70%'
      },
      {
        top: '10%',
        left: '30%',
        right: '45%'
      },
      {
        top: '10%',
        left: '55%',
        right: '20%'
      }
    ],
    xAxis: [
      {
        type: 'category',
        gridIndex: 0,
        data: xData,
        axisLine: {
          show: true,
          lineStyle: {
            color: props.widgetOptions.setup.xLineColor
          }
        },
        axisLabel: {
          color: props.widgetOptions.setup.xFontColor,
          fontSize: props.widgetOptions.setup.xFontSize
        }
      },
      {
        type: 'category',
        gridIndex: 1,
        data: xData,
        axisLine: {
          lineStyle: {
            color: props.widgetOptions.setup.xLineColor
          }
        },
        axisLabel: {
          color: props.widgetOptions.setup.xFontColor,
          fontSize: props.widgetOptions.setup.xFontSize
        }
      },
      {
        type: 'value',
        gridIndex: 2,
        max: xMax,
        splitLine: { show: false },
        axisLine: {
          lineStyle: {
            color: props.widgetOptions.setup.xLineColor
          }
        },
        axisLabel: {
          color: props.widgetOptions.setup.xFontColor,
          fontSize: props.widgetOptions.setup.xFontSize
        }
      }
    ],
    yAxis: [
      {
        type: 'value',
        gridIndex: 0,
        min: yMin,
        max: yMax,
        splitNumber: 5,
        axisLabel: {
          color: props.widgetOptions.setup.yFontColor,
          fontSize: props.widgetOptions.setup.yFontSize
        }
      },
      {
        type: 'value',
        gridIndex: 1,
        min: yMin,
        max: yMax,
        axisTick: { show: false },
        axisLabel: { show: false },
        axisLine: { show: false },
        splitNumber: 5
      },
      {
        scale: true,
        gridIndex: 2,
        min: yMin,
        max: yMax,
        axisTick: { show: false },
        axisLabel: { show: false },
        axisLine: { show: false },
        splitNumber: 5
      }
    ],
    series: series,
    graphic: [
      {
        type: 'text',
        left: 50,
        top: 20,
        style: {
          text: '返回',
          fontSize: 18
        },
        onclick: function () {
          reload()
        }
      }
    ]
  }

  const newData = Object.fromEntries(Object.entries(value).filter(([key]) => key !== 'hist'))
  tableData.value = newData
  myChart?.setOption(option)
}

const resolveData = (data: any) => {
  if (data.list && data.list.length > 0) {
    chartStatus.value = ''
    chartData.value = data.list
    updateOptions()
  } else {
    chartStatus.value = 'noData'
    chartData.value = null
  }
}

const resolveMockData = (data: any) => {
  chartData.value = data.data.list
  updateOptions()
}

const { chartStatus, refreshData } = useSignalView(
  props.widgetOptions,
  props.isPreview,
  mockDataUrl,
  resolveData,
  resolveMockData
)
onMounted(() => {
  initChart()
  refreshData()
})

// 如果父组件传入的 props.value 改变，需要更新折线图颜色等
watch(
  () => props.widgetOptions,
  () => {
    if (myChart) {
      updateOptions()
    }
  },
  { immediate: true, deep: true }
)

onBeforeUnmount(() => {
  if (myChart) {
    myChart.dispose()
  }
})
</script>

<style lang="scss" scoped>
.table-box {
  position: absolute;
  right: 0;
  top: 20px;
  z-index: 222;
}
</style>
